From 81e8a9dce6211e9632aa321ef4b915dde096df71 Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Tue, 10 Aug 2004 21:21:41 +0000 Subject: [PATCH] bitkeeper revision 1.1159.21.1 (41193c65K9NbWw4E7FhhvSPwFS3svQ) More binary-rewrite patches. --- .../arch/xen/i386/mm/fault.c | 3 +- .../arch/xen/i386/mm/pgtable.c | 13 +- .../arch/xen/kernel/fixup.c | 338 ++++++++++-------- .../include/asm-xen/asm-i386/fixmap.h | 6 +- .../include/asm-xen/asm-i386/pgtable.h | 7 +- 5 files changed, 207 insertions(+), 160 deletions(-) diff --git a/linux-2.6.7-xen-sparse/arch/xen/i386/mm/fault.c b/linux-2.6.7-xen-sparse/arch/xen/i386/mm/fault.c index d850d279d5..f508ccd8c3 100644 --- a/linux-2.6.7-xen-sparse/arch/xen/i386/mm/fault.c +++ b/linux-2.6.7-xen-sparse/arch/xen/i386/mm/fault.c @@ -248,7 +248,8 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code, * (error_code & 4) == 0, and that the fault was not a * protection error (error_code & 1) == 0. */ - if (unlikely(address >= TASK_SIZE)) { + if (unlikely(address >= TASK_SIZE) || + unlikely(address < (FIRST_USER_PGD_NR< 1) goto out; pgd_list_add(pgd); spin_unlock_irqrestore(&pgd_lock, flags); - memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t)); + memset((pgd_t *)pgd + FIRST_USER_PGD_NR, + 0, USER_PTRS_PER_PGD*sizeof(pgd_t)); out: __make_page_readonly(pgd); queue_pgd_pin(__pa(pgd)); diff --git a/linux-2.6.7-xen-sparse/arch/xen/kernel/fixup.c b/linux-2.6.7-xen-sparse/arch/xen/kernel/fixup.c index 61c5497f40..e20be71808 100644 --- a/linux-2.6.7-xen-sparse/arch/xen/kernel/fixup.c +++ b/linux-2.6.7-xen-sparse/arch/xen/kernel/fixup.c @@ -27,11 +27,12 @@ #include #include #include +#include #include #include #include -#if 0 +#if 1 #define ASSERT(_p) \ if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \ __LINE__, __FILE__); *(int*)0=0; } @@ -43,35 +44,57 @@ #define DPRINTK(_f, _a...) ((void)0) #endif +static char *fixup_buf; +#define FIXUP_BUF_USER PAGE_SIZE +#define FIXUP_BUF_ORDER 1 +#define FIXUP_BUF_SIZE (PAGE_SIZE<eip - insn_len; struct fixup_entry *fe; pte_t *pte; @@ -198,28 +224,50 @@ asmlinkage void do_fixup_4gb_segment(struct pt_regs *regs, long error_code) if ( unlikely(eip >= (PAGE_OFFSET-32)) ) { - if ( (eip < fixup_buf_user) || (eip >= (fixup_buf_user+PAGE_SIZE-32)) ) + DPRINTK("User executing out of kernel space?!"); + return; + } + + if ( unlikely(((eip ^ (eip+PATCH_LEN)) & PAGE_MASK) != 0) ) + { + DPRINTK("Patch instruction would straddle a page boundary."); + return; + } + + /* + * Check that the page to be patched is part of a read-only VMA. This + * means that our patch will never erroneously get flushed to disc. + */ + if ( eip > (FIXUP_BUF_USER + FIXUP_BUF_SIZE) ) /* don't check fixup area */ + { + /* [SMP] Need to the mmap_sem semaphore. */ + struct vm_area_struct *vma = find_vma(current->mm, eip); + if ( (vma == NULL) || (vma->vm_flags & VM_MAYSHARE) ) { - DPRINTK("User executing out of kernel space?!"); + DPRINTK("Cannot patch a shareable VMA."); return; } - /* We know it's safe to directly copy teh bytes into our buffer. */ - memcpy(b, (void *)eip, sizeof(b)); } - else if ( unlikely(copy_from_user(b, (void *)eip, sizeof(b)) != 0) ) + + if ( unlikely(copy_from_user(b, (void *)eip, sizeof(b)) != 0) ) { DPRINTK("Could not read instruction bytes from user space."); return; } - if ( unlikely(((eip ^ (eip+5)) & PAGE_MASK) != 0) ) + /* Already created a fixup for this address and code sequence? */ + hash = FIXUP_HASH(b); + for ( fe = fixup_hash[hash]; + fe != NULL; fe = fe->next ) { - DPRINTK("Patch instruction would straddle a page boundary."); - return; + if ( eip != fe->patch_addr ) + continue; /* XXX */ + if ( memcmp(fe->patched_code, b, fe->patched_code_len) == 0 ) + goto do_the_patch; } /* Guaranteed enough room to patch? */ - if ( unlikely(fixup_idx > (PAGE_SIZE-32)) ) + if ( unlikely((fi = fixup_idx) > (FIXUP_BUF_SIZE-32)) ) { static int printed = 0; if ( !printed ) @@ -268,40 +316,77 @@ asmlinkage void do_fixup_4gb_segment(struct pt_regs *regs, long error_code) return; } - while ( insn_len < 5 ) + /* Indirect jump pointer. */ + *(u32 *)&fixup_buf[fi] = FIXUP_BUF_USER + fi + 4; + fi += 4; + + /* push */ + if ( save_indirect_reg ) + fixup_buf[fi++] = 0x50 + rm; + + /* add %gs:0, */ + fixup_buf[fi++] = 0x65; + fixup_buf[fi++] = 0x03; + fixup_buf[fi++] = 0x05 | (rm << 3); + *(unsigned long *)&fixup_buf[fi] = 0; + fi += 4; + + /* Relocate the faulting instruction, minus the GS override. */ + memcpy(&fixup_buf[fi], &b[1], error_code - 1); + fi += error_code - 1; + + /* pop */ + if ( save_indirect_reg ) + fixup_buf[fi++] = 0x58 + rm; + + while ( insn_len < PATCH_LEN ) { /* Bail if can't decode the following instruction. */ if ( unlikely((new_insn_len = - get_insn_len(&b[insn_len], &opcode)) == 0) ) + get_insn_len(&b[insn_len], &opcode, &decode)) == 0) ) { DPRINTK("Could not decode following instruction."); return; } /* We track one 8-bit relative offset for patching later. */ - if ( ((opcode >= 0x70) && (opcode <= 0x7f)) || (opcode == 0xeb) ) + if ( (decode & CODE_MASK) == JMP ) { - if ( relbyte_idx != -1 ) - { - DPRINTK("Multiple relative offsets in patch seq!"); - return; - } - relbyte_idx = insn_len; - while ( b[relbyte_idx] != opcode ) - relbyte_idx++; - relbyte_idx++; + rel_idx = insn_len; + while ( (fixup_buf[fi++] = b[rel_idx++]) != opcode ) + continue; + + /* Patch the 8-bit relative offset. */ + int idx = fe->fixup_idx + relbyte_idx + 6 + 4/**/; + if ( save_indirect_reg ) + idx += 2; + fixup_buf[idx] = fi - (idx + 1); + + /* jmp */ + fixup_buf[fi++] = 0xe9; + fi += 4; + *(unsigned long *)&fixup_buf[fi-4] = + (eip + relbyte_idx + 1 + (long)(char)b[relbyte_idx]) - + (FIXUP_BUF_USER + fi); } else if ( opcode == 0xe9 ) { - if ( relword_idx != -1 ) - { - DPRINTK("Multiple relative offsets in patch seq!"); - return; - } - relword_idx = insn_len; - while ( b[relword_idx] != opcode ) - relword_idx++; - relword_idx++; + rel_idx = insn_len; + while ( (fixup_buf[fi++] = b[rel_idx++]) != opcode ) + continue; + + /* Patch the 32-bit relative offset. */ + int idx = fe->fixup_idx + relword_idx + 6 + 4/**/; + if ( save_indirect_reg ) + idx += 2; + *(unsigned long *)&fixup_buf[idx] += + (eip + relword_idx) - (FIXUP_BUF_USER + idx); + } + else + { + /* Relocate the instruction verbatim. */ + memcpy(&fixup_buf[fi], &b[insn_len], new_insn_len); + fi += new_insn_len; } if ( (insn_len += new_insn_len) > 20 ) @@ -311,7 +396,7 @@ asmlinkage void do_fixup_4gb_segment(struct pt_regs *regs, long error_code) } /* The instructions together must be no smaller than 'jmp '. */ - if ( insn_len >= 5 ) + if ( insn_len >= PATCH_LEN ) break; /* Can't have a RET in the middle of a patch sequence. */ @@ -322,120 +407,70 @@ asmlinkage void do_fixup_4gb_segment(struct pt_regs *regs, long error_code) } } - /* Already created a fixup for this address and code sequence? */ - for ( fe = fixup_hash[FIXUP_HASH(eip)]; - fe != NULL; fe = fe->next ) - { - if ( (fe->patch_addr == eip) && - (fe->patched_code_len == insn_len) && - (memcmp(fe->patched_code, b, insn_len) == 0) ) - goto do_the_patch; - } - - /* No existing patch -- create an entry for one. */ + /* Create an entry for a new fixup patch. */ fe = kmalloc(sizeof(struct fixup_entry), GFP_KERNEL); if ( unlikely(fe == NULL) ) { DPRINTK("Not enough memory to allocate a fixup_entry."); return; } - fe->patch_addr = eip; + fe->patch_addr = eip; /* XXX */ fe->patched_code_len = insn_len; memcpy(fe->patched_code, b, insn_len); fe->fixup_idx = fixup_idx; - fe->next = fixup_hash[FIXUP_HASH(eip)]; - fixup_hash[FIXUP_HASH(eip)] = fe; - - /* push */ - if ( save_indirect_reg ) - fixup_buf[fixup_idx++] = 0x50 + rm; - - /* add %gs:0, */ - fixup_buf[fixup_idx++] = 0x65; - fixup_buf[fixup_idx++] = 0x03; - fixup_buf[fixup_idx++] = 0x05 | (rm << 3); - *(unsigned long *)&fixup_buf[fixup_idx] = 0; - fixup_idx += 4; + fe->return_idx = + fixup_idx + error_code + 6 + 4/**/ + (save_indirect_reg ? 2 : 0); + fe->next = fixup_hash[hash]; + fixup_hash[hash] = fe; - /* First relocated instruction, minus the GS override. */ - memcpy(&fixup_buf[fixup_idx], &b[1], error_code - 1); - fixup_idx += error_code - 1; - - /* pop */ - if ( save_indirect_reg ) - fixup_buf[fixup_idx++] = 0x58 + rm; - - if ( insn_len != error_code ) - { - /* Relocated instructions. */ - memcpy(&fixup_buf[fixup_idx], &b[error_code], insn_len - error_code); - fixup_idx += insn_len - error_code; - } /* jmp */ - fixup_buf[fixup_idx++] = 0xe9; - fixup_idx += 4; - *(unsigned long *)&fixup_buf[fixup_idx-4] = - (eip + insn_len) - (fixup_buf_user + fixup_idx); + fixup_buf[fi++] = 0xe9; + fi += 4; + *(unsigned long *)&fixup_buf[fi-4] = + (eip + insn_len) - (FIXUP_BUF_USER + fi); - if ( relbyte_idx != -1 ) - { - /* Patch the 8-bit relative offset. */ - int idx = fe->fixup_idx + relbyte_idx + 6; - if ( save_indirect_reg ) - idx += 2; - fixup_buf[idx] = fixup_idx - (idx + 1); - - /* jmp */ - fixup_buf[fixup_idx++] = 0xe9; - fixup_idx += 4; - *(unsigned long *)&fixup_buf[fixup_idx-4] = - (eip + relbyte_idx + 1 + (long)(char)b[relbyte_idx]) - - (fixup_buf_user + fixup_idx); - } - else if ( relword_idx != -1 ) + /* Commit the patch. */ + fixup_idx = fi; + +#if 0 + if ( fe->fixup_idx == 4122 ) { - /* Patch the 32-bit relative offset by subtracting the code disp. */ - int idx = fe->fixup_idx + relword_idx + 6; - if ( save_indirect_reg ) - idx += 2; - *(unsigned long *)&fixup_buf[idx] += - (eip + relword_idx) - (fixup_buf_user + idx); + int iii; + printk(KERN_ALERT "EIP == %08lx; USER_EIP == %08lx\n", + eip, FIXUP_BUF_USER + fe->fixup_idx); + printk(KERN_ALERT " .byte "); + for ( iii = 0; iii < insn_len; iii++ ) + printk("0x%02x,", b[iii]); + printk("\n"); + printk(KERN_ALERT " .byte "); + for ( iii = fe->fixup_idx; iii < fi; iii++ ) + printk("0x%02x,", fixup_buf[iii]); + printk("\n"); + printk(KERN_ALERT " .byte "); + for ( iii = fe->fixup_idx; iii < fi; iii++ ) + printk("0x%02x,", ((char *)FIXUP_BUF_USER)[iii]); + printk("\n"); } +#endif do_the_patch: /* Create the patching instruction in a temporary buffer. */ - patch[0] = 0xe9; - *(unsigned long *)&patch[1] = - (fixup_buf_user + fe->fixup_idx) - (eip + 5); - - /* - * Check that the page to be patched is part of a read-only VMA. This - * means that our patch will never erroneously get flushed to disc. - */ - if ( eip < PAGE_OFFSET ) /* don't need to check the fixmap area */ - { - /* [SMP] Need to the mmap_sem semaphore. */ - struct vm_area_struct *vma = find_vma(current->mm, eip); - if ( (vma == NULL) || (vma->vm_flags & VM_MAYSHARE) ) - { - DPRINTK("Cannot patch a shareable VMA."); - return; - } - } + patch[0] = 0x67; + patch[1] = 0xff; + patch[2] = 0x26; /* call */ + *(u16 *)&patch[3] = FIXUP_BUF_USER + fe->fixup_idx; /* [SMP] Need to pause other threads while patching. */ pgd = pgd_offset(current->mm, eip); pmd = pmd_offset(pgd, eip); pte = pte_offset_kernel(pmd, eip); veip = kmap(pte_page(*pte)); - memcpy((char *)veip + (eip & ~PAGE_MASK), patch, 5); + memcpy((char *)veip + (eip & ~PAGE_MASK), patch, PATCH_LEN); kunmap(pte_page(*pte)); /* Success! Return to user land to execute 2nd insn of the pair. */ - regs->eip = fixup_buf_user + fe->fixup_idx + error_code + 6; - if ( save_indirect_reg ) - regs->eip += 2; + regs->eip = FIXUP_BUF_USER + fe->return_idx; return; } @@ -443,7 +478,9 @@ static int nosegfixup = 0; static int __init fixup_init(void) { - unsigned long page; + struct vm_struct vma; + struct page *_pages[1<> PGDIR_SHIFT) #define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS) #define TWOLEVEL_PGDIR_SHIFT 22 #define BOOT_USER_PGD_PTRS (__PAGE_OFFSET >> TWOLEVEL_PGDIR_SHIFT) #define BOOT_KERNEL_PGD_PTRS (1024-BOOT_USER_PGD_PTRS) - +#endif #ifndef __ASSEMBLY__ /* Just any arbitrary offset to the start of the vmalloc VM area: the -- 2.30.2